package com.modular.extra.ai.task;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.*;
import cn.hutool.cron.CronUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import com.c.Constant;
import com.c.opt.tool.ToolEntity;
import com.modular.event.AlarmEventApi;
import com.modular.event.bean.AlarmEventDO;
import com.modular.event.bo.AlarmInBO;
import com.modular.extra.ai.FactoryAiOpt;
import com.modular.extra.ai.vision.airesult.bean.AiResultDO;
import com.modular.extra.ai.vision.record.bean.AiRecord;
import com.modular.extra.fm.FactoryFmOpt;
import com.modular.extra.fm.om.bean.FmOmUserDo;
import ntd.remote.file.ComRemoteFile;
import ntd.remote.file.bo.ComRemoteFileBO;
import ntd.remote.link.ComRegistryClient;
import ntd.sys.ToolJvm;
import ntd.task.Task;
import ntd.task.bo.TaskInfo;
import ntd.tool.ToolCron;
import ntd.util.UtilCatch;
import ntd.util.config.common.exception.ComException;
import ntd.util.frame.javacv.action.bean.VisionModelDo;
import ntd.util.frame.javacv.config.AiConfig;
import ntd.util.frame.javacv.remote.AiVisionRemote;
import ntd.util.frame.storage.bo.StorageOutBO;
import ntd.util.frame.storage.tool.ToolStorage;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

import static ntd.util.frame.javacv.ComVisionApi.analysisRemoteList;

/**
 * 机器视觉轮询分析任务
 */
public class VisionAnalysisHandleResultTask implements Task {
    @Override
    public TaskInfo info() {
        return new TaskInfo("任务-机器视觉结果同步到本地", "task-vision-analysis-sync-local-20230607", new VisionAnalysisHandleResultTask());
    }

    @Override
    public void execute(Object o) {
        for (AiVisionRemote aiVisionRemote : analysisRemoteList()) {
            ComRemoteFileBO comRemoteFileBO = new ComRemoteFileBO();
            comRemoteFileBO.setRemoteCode(aiVisionRemote.aiServerDo.getCode());
            comRemoteFileBO.setPath(AiConfig.AI_BASE_DATA_PATH);
            List<ComRemoteFileBO> comRemoteFileBOS = ComRemoteFile.me.loopListFiles(comRemoteFileBO);

            Map<String, List<ComRemoteFileBO>> listMap = CollStreamUtil.groupByKey(comRemoteFileBOS, comRemoteFileBO1 -> {
                String name = comRemoteFileBO1.getName();
                String[] split = name.split("-");
                try {
                    return split[0] + split[1] + split[2] + split[3];
                } catch (Exception e) {
                    StaticLog.info("错误文件信息 - [{}]", name);
                    return null;
                }
            });

            // 遍历文件
            for (List<ComRemoteFileBO> remoteFileBOS : listMap.values()) {
                UtilCatch.tryCatchNoRes(() -> handle(aiVisionRemote, remoteFileBOS));
            }

        }
    }

    private static void handle(AiVisionRemote aiVisionRemote, List<ComRemoteFileBO> remoteFileBOS) {
        ComRemoteFileBO json = CollUtil.findOne(remoteFileBOS, item -> FileNameUtil.getSuffix(item.getName()).equals("json"));
        ComRemoteFileBO file = CollUtil.findOne(remoteFileBOS, item -> FileNameUtil.isType(item.getName(), "jpg", "png", "mp4"));
        if (ObjectUtil.isNull(json) || ObjectUtil.isNull(file)) {
            return;
        }
        json.setRemoteCode(aiVisionRemote.aiServerDo.getCode());
        file.setRemoteCode(aiVisionRemote.aiServerDo.getCode());
        String jsonText = new String(ComRemoteFile.me.readFile(json), StandardCharsets.UTF_8);

        // 读取json判定是否有异常
        String modeTypeTag = isHaveAlertThings(jsonText);

        // 判断是否在线文件
        if (!StrUtil.contains(file.getName(), AiConfig.AI_ONLINE_FILE_ANALYSIS)) {
            AiRecord aiRecord = FactoryAiOpt.OPT_AI_RECORD.query().eq("file_name", file.getName()).getBean();
            if (ObjectUtil.isNull(aiRecord)) {
                return;
            }
            aiRecord.setTextJson(jsonText);
            if (StrUtil.isBlank(modeTypeTag) || "无".equals(modeTypeTag)) {
                aiRecord.setIsException("false");
            } else {
                // 保存文件
                synchronized (VisionAnalysisHandleResultTask.class) {
                    ThreadUtil.sleep(1000);
                    StorageOutBO storageOutBO = ToolStorage.save("ai-vision", ComRemoteFile.me.readFile(file), file.getName());
                    aiRecord.setLinkUrl(storageOutBO.getFileUrl());
                }
                aiRecord.setIsException("true");

                // 兼容之前逻辑 - 保存异常数据
                handleOld(modeTypeTag, aiRecord);

                VisionModelDo byModeCode = FactoryAiOpt.OPT_VISION_MODEL.getByModeCode(aiRecord.getAiModeType());

                // 生成告警事件
                AlarmInBO alarmInBO = new AlarmInBO();
                alarmInBO.setAlarmEventCode(getEventCodeByAiModelCode(aiRecord.getAiModeType()));
                alarmInBO.setAlarmTitle(StrUtil.format("机器视觉 - [{}]预警", modeTypeTag));
                alarmInBO.setAlarmDesc(StrUtil.format("您的基站[{}]与[{}]由AI智能视觉分析察觉异常[{}]，特进行预警处理，请尽快核实处理。",
                        aiRecord.getPointCode(), aiRecord.getAnalyticsTime(), byModeCode.getName()));
                alarmInBO.setHandlerType("2");
                alarmInBO.setSourceCode("富铭科技-机器视觉");
                alarmInBO.setPointCode(aiRecord.getPointCode());
                alarmInBO.setAlarmFile(aiRecord.getLinkUrl());
                Opt.ofNullable(FactoryFmOpt.FM_SITE_OPT.getByMn(aiRecord.getPointCode())).ifPresent(fmSiteInfoDo -> {
                    alarmInBO.setPointName(fmSiteInfoDo.getSiteName());
                    Opt.ofNullable(FactoryFmOpt.FM_SITE_OPT.getOmUser(aiRecord.getPointCode())).ifPresent(fmOmUserDo -> {
                       alarmInBO.setHandler(fmOmUserDo.getId());
                       alarmInBO.setHandlerName(fmOmUserDo.getRealName());
                    });
                });
                AlarmEventApi.alarmEvent(alarmInBO);
            }
            // 更新数据
            FactoryAiOpt.OPT_AI_RECORD.syncBean(aiRecord);

            // 删除执行过的文件
            for (ComRemoteFileBO remoteFileBO : remoteFileBOS) {
                remoteFileBO.setRemoteCode(aiVisionRemote.aiServerDo.getCode());
                ComRemoteFile.me.del(remoteFileBO);
            }
        }
    }

    public static String getEventCodeByAiModelCode(String aiModelCode) {
        switch (aiModelCode) {
            case "Person": return "machine-vision-personnel-intrusion";
            case "WaterGarbage": return "machine-vision-water-garbage-intrusion";
            case "Water": return "machine-vision-water-intrusion";
            case "VehicleType": return "machine-vision-vehicle-intrusion";
            case "Algae": return "machine-vision-algae-intrusion";
            case "All": return "machine-vision-all-intrusion";
            default: throw new ComException("找不到对应告警事件类型");
        }
    }

    private static void handleOld(String modeTypeTag, AiRecord aiRecord) {
        // 验证十分钟内是否有告警
        DateTime dateTime = DateUtil.offsetMinute(DateUtil.date(), -10);
        List<AiResultDO> aiResultDOS = FactoryAiOpt.OPT_AI_RESULT.query()
                .ge("create_time", DateUtil.formatDateTime(dateTime))
                .eq("siteMn", aiRecord.getPointCode())
                .eq("ai_mode_type", aiRecord.getAiModeType())
                .listBean();

        if (CollUtil.isEmpty(aiResultDOS)) {
            AiResultDO aiResultDO = new AiResultDO();
            aiResultDO.setImageName(aiRecord.getFileName());
            aiResultDO.setSiteMn(aiRecord.getPointCode());
            aiResultDO.setCameraIndexCode(aiRecord.getCameraIndexCode());
            aiResultDO.setImageUrl(aiRecord.getLinkUrl());
            aiResultDO.setIsAlert("1");
            aiResultDO.setAlert_type(modeTypeTag);
            aiResultDO.setAi_mode_type(aiRecord.getAiModeType());
            aiResultDO.setTextJson(aiRecord.getTextJson());
            aiResultDO.setAnalytics_time(DateUtil.format(DateUtil.parse(aiRecord.getAnalyticsTime()), Constant.DATE_FORMAT_WLW_TWO));
            aiResultDO.setCreate_time(DateUtil.now());
            FactoryAiOpt.OPT_AI_RESULT.sync(ToolEntity.toEntity(aiResultDO, false));
        }
    }

    //json是否含有告警物体
    private static String isHaveAlertThings(String json) {
        return UtilCatch.tryCatch(() -> {
            if (JSONUtil.isTypeJSON(json)) {
                JSONArray jsonArray = JSONUtil.parseArray(json);
                if (jsonArray.size() > 0 ) {

                    String[] things = new String[jsonArray.size()];
                    for (int i = 0;i < jsonArray.size();i++){
                        if (jsonArray.getJSONObject(i) != null)
                            things[i] = jsonArray.getJSONObject(i).get("物体").toString();
                    }
                    return ArrayUtil.join(things,",");
                }
            }
            //默认是无=无检测物体
            return null;
        });
    }

    public static void main(String[] args) throws Exception {
        ThreadUtil.execAsync(() -> ComRegistryClient.run("client-code-" + RandomUtil.randomString(10), "客户端-测试", "61.52.247.249", 13021));

        ThreadUtil.sleep(3000);

        VisionAnalysisHandleResultTask visionAnalysisTask = new VisionAnalysisHandleResultTask();

        // 设置不允许退出
        ToolJvm.setNoExit();
        // 设置定时任务
//        CronUtil.schedule("40 * * * * *", (Runnable) () ->  visionAnalysisTask.execute(null));
        visionAnalysisTask.execute(null);
        // 启动定时任务
        ToolCron.initTask();
    }
}
